package net.web.belerofont.controller;

import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import net.web.belerofont.action.Action;
import net.web.belerofont.action.Interceptor;
import net.web.belerofont.action.URIMap;
import net.web.belerofont.action.support.URIMapSupport;

import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

public class ConfigXMLReader extends ConfigReader {
	public static final Logger LOG = Logger.getLogger(ConfigXMLReader.class);

	private Map<String, Action> actionMap;
	List<Interceptor> globalInterceptorsList;
	Map<String, List<Interceptor>> localInterceptorsMap;

	protected ConfigXMLReader() {
		actionMap = new HashMap<String, Action>();
		globalInterceptorsList = new LinkedList<Interceptor>();
		localInterceptorsMap = new HashMap<String, List<Interceptor>>();
	}

	public ConfigXMLReader(String fileName) throws CreateConfigException {
		this();
		try {
			SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(new File(fileName));
			read(doc);
		} catch (Exception ex) {
			throw new CreateConfigException(ex);
		}

	}

	public ConfigXMLReader(InputStream inputStream)
			throws CreateConfigException {
		this();
		try {
			SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(inputStream);
			read(doc);
		} catch (Exception ex) {
			throw new CreateConfigException(ex);
		}
	}

	private void read(Document doc) throws ClassNotFoundException,
			InstantiationException, IllegalAccessException, JDOMException {
		Action localAction = null;
		URIMap localURIMap;
		
		XPath interceptorPath = XPath.newInstance("//config"); 
		
		if (interceptorPath != null && interceptorPath.selectNodes(doc).size() > 0) {
			List<Element> interceptorList = interceptorPath.selectNodes(doc);
			
			if (interceptorList.get(0).getChild("interceptors") != null) {
			
				List<Element> interceptors = interceptorList.get(0).getChild("interceptors").getChildren("interceptor");
				if (interceptors != null && interceptors.size() > 0 ) {
					Iterator<Element> iinterceptors = interceptors.iterator();
					LOG.debug("Global Interceptors:");
					while (iinterceptors.hasNext()) {
						Element interceptor = iinterceptors.next();
						this.globalInterceptorsList
								.add(getInterceptorByClassName(interceptor
										.getAttributeValue("class")));
						LOG.debug("\t" + interceptor.getAttributeValue("class"));
					}
				}
			
			}
		}
		

		XPath actionPath = XPath.newInstance("//action");
		List<Element> actions = actionPath.selectNodes(doc);
		Iterator<Element> i = actions.iterator();
		while (i.hasNext()) {
			Element action = i.next();

			LOG.debug("Action: " + action.getAttributeValue("path"));

			localAction = getActionByClassName(action
					.getAttributeValue("class"));
			this.actionMap.put(action.getAttributeValue("path"), localAction);

			if (action.getChild("forwards") != null) {
				Map<String, URIMap> uris = new HashMap<String, URIMap>();
				List<Element> forwards = action.getChild("forwards").getChildren("forward");
				Iterator<Element> iforwards = forwards.iterator();
				LOG.debug("Forwards:");
				while (iforwards.hasNext()) {
					Element forward = iforwards.next();
					localURIMap = URIMapSupport.instance(forward
							.getAttributeValue("path"), forward
							.getAttributeValue("transferType"));
					LOG.debug("\t" + forward.getAttributeValue("name") + "::"
							+ forward.getAttributeValue("path"));

					uris.put(forward.getAttributeValue("name"), localURIMap);
				}
				localAction.init(uris);
			}
			if (action.getChild("interceptors") != null) {
				List<Interceptor> localInterceptors = new LinkedList<Interceptor>();
				
				List<Element> interceptors = action.getChild("interceptors").getChildren("interceptor");
				Iterator<Element> iinterceptors = interceptors.iterator();
				LOG.debug("Interceptors:");
				while (iinterceptors.hasNext()) {
					Element interceptor = (Element) iinterceptors.next();
					localInterceptors.add(getInterceptorByClassName(interceptor
							.getAttributeValue("class")));
					LOG.debug("\t" + interceptor.getAttributeValue("class"));
				}
				this.localInterceptorsMap.put(action.getAttributeValue("path"),
						localInterceptors);
			}
		}
	}

	public Map<String, Action> getActions() {
		return actionMap;
	}

	public List<Interceptor> getGlobalInterceptors() {
		return globalInterceptorsList;
	}

	public List<Interceptor> getInterceptors(String actionPath) {
		List<Interceptor> list = new LinkedList<Interceptor>();
		list.addAll(globalInterceptorsList);
		list.addAll(getLocalInterceptors(actionPath));
		return list;
	}

	public List<Interceptor> getLocalInterceptors(String actionPath) {
		return localInterceptorsMap.get(actionPath);
	}

}
